/***
 * 原始产生式：
 * expr ->      expr + term
 *          |   expr - term
 *          |   term
 * term ->  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
 * 翻译方案：
 * expr ->      expr + term {printf("+")}
 *          |   expr - term {printf("-")}
 *          |   term
 * term ->      '0' {printf("0")}
 *          |   '1' {printf("1")}
 *          |   '2' {printf("1")}
 *          |   '3' {printf("1")}
 *          |   '4' {printf("1")}
 *          |   '5' {printf("1")}
 *          |   '6' {printf("1")}
 *          |   '7' {printf("1")}
 *          |   '8' {printf("1")}
 *          |   '9' {printf("1")}
 *
 * 消除左递归之后的翻译方案：
 * expr ->      term rest
 * rest ->      + term {printf("+")} rest
 *          |   - term {printf("-")} rest
 *          |   ε
 */

#include "postfix.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "def.h"
#include "log.h"
#include "../lex/lex.h"

/**
 * @brief expr解析
 *
 * @param data 输入数据
 * @param len 输入数据长度
 * @return int32_t >= 0已处理的数据长度 ; < 0 处理失败
 *
 * expr ->      term rest
 */
static int32_t expr(
    lex_st *lex);

/**
 * @brief term 解析
 *
 * @param data 输入数据
 * @param len 输入数据长度
 * @return int32_t >= 0已处理的数据长度 ; < 0 处理失败
 *
 * term ->      num {printf("%ld", num)}
 *          |   '(' expr ')'
 */

/**
 * @brief term 解析
 *
 * @param lex 词法分析器
 * @return int32_t < 0 解析失败; ==0 解析成功
 */
static int32_t term(
    lex_st *lex)
{
    symbol_st *symbol = lex_get_symbol(lex);
    if (symbol == NULL)
    {
        ERR_FUNC_LINE("get symbol failed!\n");
        return -1;
    }

    if (symbol->type == symbol_type_num)
    {
        NOTICE("<%ld>", symbol->value);
        return 0;
    }
    else if (symbol->type == symbol_type_open_parenthesis)
    {
        int32_t ret = expr(lex);
        if (ret < 0)
        {
            ERR_FUNC_LINE("expr failed!\n");
            return -1;
        }

        symbol = lex_get_symbol(lex);
        if ((symbol == NULL) || (symbol->type != symbol_type_close_parenthesis))
        {
            ERR_FUNC_LINE("symbol type isn't close parenthesis\n");
            return -1;
        }
    }
    else
    {
        ERR_FUNC_LINE("symbol type isn't close parenthesis\n");
        return -1;
    }
    return 0;
}

/**
 * @brief rest解析
 *
 * @param data 输入数据
 * @param len 输入数据长度
 * @return int32_t >= 0已处理的数据长度 ; < 0 处理失败
 *
 * rest ->      + term {printf("+")} rest
 *          |   - term {printf("-")} rest
 *          |   ε
 */
static int32_t rest(
    lex_st *lex)
{
    symbol_st *symbol = lex_get_symbol(lex);
    if (symbol == NULL)
    {
        /* ε */
        return 0;
    }
    if (symbol->type == symbol_type_plus)
    {
        int32_t ret = term(lex);
        if (ret < 0)
        {
            ERR_FUNC_LINE("term failed!\n");
            return -1;
        }
        NOTICE("+");

        ret = rest(lex);
        if (ret < 0)
        {
            ERR_FUNC_LINE("rest failed!\n");
            return -1;
        }
    }
    else if (symbol->type == symbol_type_minus)
    {
        int32_t ret = term(lex);
        if (ret < 0)
        {
            ERR_FUNC_LINE("term failed!\n");
            return -1;
        }
        NOTICE("-");

        ret = rest(lex);
        if (ret < 0)
        {
            ERR_FUNC_LINE("rest failed!\n");
            return -1;
        }
    }
    else
    {
        /* ε */
        if (lex_put_symbol(lex, symbol) < 0)
        {
            ERR_FUNC_LINE("lex_put_symbol err!\n");
        }
    }
    return 0;
}

/**
 * @brief expr解析
 *
 * @param lex 词法分析器
 * @return int32_t: 0 分析成功; <0 分析失败
 */
static int32_t expr(
    lex_st *lex)
{
    int32_t ret = term(lex);
    if (ret < 0)
    {
        ERR_FUNC_LINE("term failed!\n");
        return -1;
    }

    ret = rest(lex);
    if (ret < 0)
    {
        ERR_FUNC_LINE("rest failed!\n");
        return -1;
    }

    return 0;
}

/**
 * @brief postfix自测函数
 *
 * @return int 测试失败
 */
int postfix_test(
    void)
{
    FUNC_BEGIN();
    char *path = "./test_data.txt";
    lex_st *lex = lex_malloc(path);
    assert(lex != NULL);

    int32_t ret = expr(lex);
    assert(ret == 0);
    NOTICE("\n");
    lex_free(lex);
    FUNC_FINISH();
    return 0;
}
